package com.yixing.tech.entity.service.impl;

import org.apache.commons.lang3.StringUtils;
import com.yixing.tech.common.base.BaseMongoDao;
import com.yixing.tech.common.base.BusinessException;
import com.yixing.tech.common.base.ConditionsVO;
import com.yixing.tech.common.enums.ErrCode;
import com.yixing.tech.common.enums.YesOrNo;
import com.yixing.tech.entity.entity.CustomActionParam;
import com.yixing.tech.entity.po.EntityData;
import com.yixing.tech.entity.po.Obj;
import com.yixing.tech.entity.service.EntityBaseService;
import com.yixing.tech.entity.service.IEntityService;
import com.yixing.tech.entity.utils.EntityUtils;
import com.yixing.tech.common.utils.CommonUtil;
import com.yixing.tech.common.utils.ExcelUtil;
import com.yixing.tech.common.vo.s3.DepartmentVO;
import com.yixing.tech.common.vo.s3.UserVO;
import com.yixing.tech.common.vo.s5.EntitiesVO;
import com.yixing.tech.common.vo.s5.EntityVO;
import com.yixing.tech.common.vo.s5.EntitySchema;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.mongodb.core.BulkOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.util.Pair;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @author yixing tech
 */
@Service
@Slf4j
public class EntityServiceImpl implements IEntityService {

    @Lazy
    @Autowired
    private EntityBaseService ebs;
    @Resource
    BaseMongoDao baseMongoDao;
    @Resource
    MongoTemplate mongoTemplate;
    @Value("${tenant-id: 6204cb763da841718ddd1cf8}")
    private String tenantId;
    @Resource
    RedisTemplate<String, Object> redisTemplate;

    @Override
    public String insert(EntityVO vo) throws BusinessException {
        String objId = getObjId(vo.getObjName());
        if (ObjectUtils.isEmpty(objId)) throw new BusinessException(ErrCode.PARAMETER_ERROR);
        Map map = vo.getEntity();
        map.put("tenantId", tenantId);
        map.remove("id");
        Date date = new Date();
        map.put("createTime", date);
        map.put("updateTime", date);
        EntityData entity = new EntityData();
        beforeInsertBiz(objId, map);
        entity.putAll(map);

        if ("64bf6f57558136382dc87f79".equals(objId)) {
            // 覆盖逻辑
            String cartonNo = map.get("CartonNo").toString();
            Query checkQuery = Query.query(
                    Criteria.where("isDelete").ne(YesOrNo.YES.ordinal())
                            .and("CartonNo").is(cartonNo)
                            .and("是否已出库").is(false)
            );
            Document one = mongoTemplate.findOne(checkQuery, Document.class, "entity_" + "64bf6f57558136382dc87f79");
            if (one != null) {
                Document document = new Document(map);
                document.put("isDelete", YesOrNo.NO.ordinal());
                Update update = Update.fromDocument(document);
                update.set("updateTime", new Date());
                String id = one.getString("id");
                mongoTemplate.updateFirst(Query.query(Criteria.where("_id").is(new ObjectId(id))), update, "entity_" + "64bf6f57558136382dc87f79");
                return id;
            } else {
                return ebs.insetEntity(objId, entity);
            }
        } else {
            String id = ebs.insetEntity(objId, entity);
            return id;
        }
    }

    private void beforeInsertBiz(String objId, Map map) {
        if("64bf6f57558136382dc87f79".equals(objId)) {
            map.put("是否已出库", false);
            map.put("是否出库中", false);
        }
    }

    @Override
    public void batchInsert(EntitiesVO vo) throws BusinessException {
        String objId = getObjId(vo.getObjName());
        if (ObjectUtils.isEmpty(objId)) throw new BusinessException(ErrCode.PARAMETER_ERROR);
        List<Map> entities = vo.getEntities();
        if (CommonUtil.listIsBlank(entities)) throw new BusinessException(ErrCode.PARAMETER_ERROR);
        Date date = new Date();
        for (Map map : entities) {
            map.put("tenantId", tenantId);
            map.put("createTime", date);
            map.put("updateTime", date);
            map.put("isDelete", YesOrNo.NO.ordinal());

            // 定制化处理
//            try {
//                if("外箱标签".equals(vo.getObjName())) {
//                    String productCode = map.getOrDefault("Product", "").toString();
//                    if(productCode.startsWith("F0680")) {
//                        map.put("Product", "10020038");
//                        map.put("ProductBak", productCode);
//                    }
//                }
//            } catch (Throwable e) {
//                log.error("定制化处理失败: {}", map, e);
//            }
        }
        ebs.insetEntitys(objId, entities, null);
    }


    @Override
    public void update(EntityVO vo) throws BusinessException {
        String objId = getObjId(vo.getObjName());
        if (ObjectUtils.isEmpty(objId)) throw new BusinessException(ErrCode.OBJ_NOT_EXIST);
        ConditionsVO conditionsVO = new ConditionsVO();
        conditionsVO.setTenantId(tenantId);
        conditionsVO.setConditions(vo.getConditions());
        Criteria criteria = new Criteria().andOperator(baseMongoDao.condition2CriteriaList(conditionsVO));
        Query query = new Query(criteria);
        Map map = vo.getEntity();
        EntityData entity = new EntityData();
        for (Object key : map.keySet()) {
            Object value = map.get(key);
            if (null == value) continue;
            entity.put(key.toString(), value);
        }
        Document document = mongoTemplate.findOne(query, Document.class, "entity_" + objId);
        //wms 的接口
        if (objId.equals("64c725d64d1a5541d57a186f") || objId.equals("64ca10ce49c5bd1b9d0f6171") ||
                objId.equals("64dda28f28f8c812823f5a83") || objId.equals("64dda2873a43204e2138513e")
                || objId.equals("64c7532c4d1a5541d57a1885") || objId.equals("64ca198249c5bd1b9d0f6174")) {
            if (document == null) throw new BusinessException(ErrCode.DATA_NOT_EXIST);
            String status = map.getOrDefault("状态", "").toString();
            if (!"完成".equals(status)) throw new BusinessException(ErrCode.PARAMETER_ERROR);
            String currStatus = document.getString("状态");
            if ("完成".equals(currStatus)) throw new BusinessException(ErrCode.RECEIPT_OVER);
            Object isCancel = document.get("是否撤销");
            if (isCancel != null && Boolean.getBoolean(isCancel.toString())) {
                throw new BusinessException(ErrCode.RECEIPT_CANCEL);
            }

            updateYCLStock(document, objId, map);
            updateLowStock(document, objId, map);
            entity.put("id", document.getString("id"));
            ebs.updateEntity(objId, entity);
        } else if (objId.equals("64c759272521ce161ab77627")) {
            //成品出库
            String currStatus = document.getString("状态");
            String status = map.getOrDefault("状态", "").toString();
            if (!"完成".equals(status) && !"撤销".equals(status)) throw new BusinessException(ErrCode.PARAMETER_ERROR);
            Object isCancel = document.get("是否撤销");
            if (isCancel != null && Boolean.getBoolean(isCancel.toString())) {
                throw new BusinessException(ErrCode.RECEIPT_CANCEL);
            }
            if ("完成".equals(status) && !ObjectUtils.isEmpty(currStatus))
                throw new BusinessException(ErrCode.RECEIPT_OVER);
            if ("撤销".equals(status) && !"完成".equals(currStatus))
                throw new BusinessException(ErrCode.PARAMETER_ERROR);
            updateCPStock(document, objId, map);
            entity.put("id", document.getString("id"));
            if ("撤销".equals(status)) entity.put("状态", "");
            entity.put("审核时间", new Date());
            ebs.updateEntity(objId, entity);
        } else if (objId.equals("68f1f7e29611b117745d5ae4")) {
            //成品单箱出库(新)
            String currStatus = document.getString("状态");
            String status = map.getOrDefault("状态", "").toString();
            if (!"完成".equals(status) && !"撤销".equals(status)) throw new BusinessException(ErrCode.PARAMETER_ERROR);
            Object isCancel = document.get("是否撤销");
            if (isCancel != null && Boolean.getBoolean(isCancel.toString())) {
                throw new BusinessException(ErrCode.RECEIPT_CANCEL);
            }
            if ("完成".equals(status) && !ObjectUtils.isEmpty(currStatus))
                throw new BusinessException(ErrCode.RECEIPT_OVER);
            if ("撤销".equals(status) && !"完成".equals(currStatus))
                throw new BusinessException(ErrCode.PARAMETER_ERROR);
            updateCPStockNew(document, objId, map);
            entity.put("id", document.getString("id"));
            if ("撤销".equals(status)) entity.put("状态", "");
            entity.put("审核时间", new Date());
            ebs.updateEntity(objId, entity);
        } else {
            if (document != null) {
                entity.put("id", document.getString("id"));
                ebs.updateEntity(objId, entity);
            } else {
                insert(vo);
            }
        }
    }

    @Override
    public void remove(EntityVO vo) throws BusinessException {
        String objId = getObjId(vo.getObjName());
        if (ObjectUtils.isEmpty(objId)) throw new BusinessException(ErrCode.PARAMETER_ERROR);
        ConditionsVO conditionsVO = new ConditionsVO();
        conditionsVO.setTenantId(tenantId);
        conditionsVO.setConditions(vo.getConditions());
        Criteria criteria = new Criteria().andOperator(baseMongoDao.condition2CriteriaList(conditionsVO));
        Query query = new Query(criteria);
        Update update = new Update();
        update.set("isDelete", YesOrNo.YES.ordinal());
        mongoTemplate.updateMulti(query, update, "entity_" + objId);
    }


    /**
     * 导出成品入库单明细
     */
    @Override
    public void exportProdDetail(HttpServletResponse response, String prodInStockId) throws BusinessException {
        Document document = ebs.getEntity("64c759272521ce161ab77627", prodInStockId, null, false);
        List<String> itemStrs = new ArrayList<>();
        List items  = (List) document.get("成品列表");
        if(items != null) {
            for (Object item : items) {
                if(item instanceof String) {
                    itemStrs.add(item.toString());
                } else if (item instanceof Map) {
                    itemStrs.add(((Map<?, ?>) item).get("id").toString());
                }
            }
        }
        ConditionsVO cond1 = new ConditionsVO();
        List<ConditionsVO.Condition> conditionlist = new ArrayList<>();
        ConditionsVO.Condition conditions = new ConditionsVO.Condition();
        conditions.setKey("_id");
        conditions.setSymbol("in");
        conditions.setValue(itemStrs);
        conditionlist.add(conditions);
        cond1.setConditions(conditionlist);
        List<Document> list = ebs.list(cond1, "64bf6f57558136382dc87f79", null);
        EntitySchema cond = ebs.queryByTableId("64bf6f57558136382dc87f79");
        ExcelUtil.exportEntityToExcel(response, cond.getName() + ".xls", list, cond.getAttrs());
    }

    /**
     * 单箱成品入库明细导出
     */
    @Override
    public void singleExportProdDetail(HttpServletResponse response, String prodInStockId) throws BusinessException {
        Document document = mongoTemplate.findOne(Query.query(EntityUtils.newCriteria().and("_id").is(new ObjectId(prodInStockId))),
                Document.class, "entity_" + "68f1f7e29611b117745d5ae4");
        if(document == null) {
            throw new BusinessException("无此单据!");
        }
        final String itemStr = document.getString("箱号");
        ConditionsVO cond1 = new ConditionsVO();
        List<ConditionsVO.Condition> conditionlist = new ArrayList<>();
        ConditionsVO.Condition conditions = new ConditionsVO.Condition();
        conditions.setKey("CartonNo");
        conditions.setSymbol("is");
        conditions.setValue(itemStr);
        conditionlist.add(conditions);
        cond1.setConditions(conditionlist);
        List<Document> list = ebs.list(cond1, "68ecb895903e14692f06f8fa", null);
        EntitySchema cond = ebs.queryByTableId("68ecb895903e14692f06f8fa");
        ExcelUtil.exportEntityToExcel(response, cond.getName() + ".xls", list, cond.getAttrs());
    }

    /**
     * 根据入库单生成返工领料单
     */
    @Override
    public void buildBomRQOrderByProdInStockId(String prodInStockId, UserVO userVO) throws BusinessException {
        Document document = ebs.getEntity("64c759272521ce161ab77627", prodInStockId, null, false);
        if (document == null) throw new BusinessException(ErrCode.DATA_NOT_EXIST);
        Document productOrder = document.get("生产订单", Document.class);
        String orderCode = productOrder.getString("工单编号");
        Document planOrder = mongoTemplate.findOne(Query.query(Criteria.where("源头单据号").is(orderCode).and("isDelete").ne(1)), Document.class, "entity_64c1d61afb1d976ceaff0d01");
        if (planOrder == null) throw new BusinessException(ErrCode.DATA_NOT_EXIST);
        String productCode = planOrder.getString("产品编码");
        List<Document> mList = planOrder.getList("物料清单", Document.class);
        Document material = null;
        for (Document d : mList) {
            if (productCode.equals(d.getString("材料编码"))) {
                material = d;
                break;
            }
        }
        if (material == null) throw new BusinessException(ErrCode.DATA_NOT_EXIST);
        List<String> itemStrs = document.getList("成品列表", String.class);
        ConditionsVO cond1 = new ConditionsVO();
        List<ConditionsVO.Condition> conditionlist = new ArrayList<>();
        ConditionsVO.Condition conditions = new ConditionsVO.Condition();
        conditions.setKey("_id");
        conditions.setSymbol("in");
        conditions.setValue(itemStrs);
        conditionlist.add(conditions);
        cond1.setConditions(conditionlist);
        List<Document> list = ebs.list(cond1, "64bf6f57558136382dc87f79", null);
        List<Map> contents = new ArrayList<>();
        conditions.setKey("物料");
        conditions.setSymbol("is");
        conditions.setValue(productCode);
        ConditionsVO.Condition conditions1 = new ConditionsVO.Condition();
        conditions1.setKey("批号");
        conditions1.setSymbol("is");
        conditionlist.add(conditions1);
        for (Document d : list) {
            Map m = new HashMap();
            conditions1.setValue(d.getString("Recipe"));
            List<Document> stocks = ebs.list(cond1, "64dc91ca7e0df27401298db1", null);
            if (CommonUtil.listIsBlank(stocks)) throw new BusinessException(ErrCode.DATA_NOT_EXIST);
            Document stock = stocks.get(0);
            m.put("物料类型", material);
            m.put("库存数量", stock.get("数量"));
            m.put("数量", d.get("Qty"));
            m.put("物料名称", stock.get("物料名称"));
            m.put("物料规格", stock.get("规格型号"));
            m.put("编码", productCode);
            m.put("选择库存", stock);
            contents.add(m);
        }

        EntityData vo = new EntityData();
        vo.put("createId", userVO.getId());
        vo.put("createName", userVO.getName());
        vo.put("tenantId", userVO.getTenantId());
        DepartmentVO departmentVO = userVO.getDepartment();
        if (departmentVO != null)
            vo.put("departmentId", departmentVO.getId());
        Date date = new Date();
        vo.put("createTime", date);
        vo.put("updateTime", date);
        vo.put("单据类型", "64e197b79b8f1972c0e0f90a");
        vo.put("成本中心", "64c72975f607ea2da1f86fb5");
        vo.put("调入仓库", "67ad5f2b515ebe325bd2a2d6");
        vo.put("调出仓库", "67ad5f2b515ebe325bd2a2e2");
        vo.put("领用人", userVO.getId());
        vo.put("领用时间", date.getTime());
        vo.put("所属备料计划单", planOrder.getString("id"));
        vo.put("是否已冲销", false);
        vo.put("物料清单", contents);
        vo.put("备注", document.getString("入库单号"));
        ebs.insetEntity("64c725d64d1a5541d57a186f", vo);
    }

    /**
     * 包装管制
     *
     * @param cartonNo 外箱号
     */
    @Override
    public void packControl(String cartonNo) throws BusinessException {
        String conditionObjId = "entity_6538b7cef0432a7ca7776b91";
        String cartonObjId = "entity_64bf6f57558136382dc87f79";
        String boxObjId = "entity_64bf6f3d337d8f2b242a847c";

        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");

//        List<Document> conditionList =  mongoTemplate.find(Query.query(Criteria.where("状态").is("true")), Document.class, conditionObjId);
        ConditionsVO cndVO = new ConditionsVO();
        cndVO.setTenantId(tenantId);
        List<ConditionsVO.Condition> condList = new ArrayList<>();
        cndVO.setConditions(condList);
        ConditionsVO.Condition cond1 = new ConditionsVO.Condition();
        cond1.setKey("状态");
        cond1.setSymbol("is");
        cond1.setValue(true);
        condList.add(cond1);
        List<Document> conditionList = ebs.list(cndVO, "6538b7cef0432a7ca7776b91", null);

        Document cartonDoc = mongoTemplate.findOne(Query.query(Criteria.where("CartonNo").is(cartonNo)), Document.class, cartonObjId);
        if (cartonDoc == null) {
            throw new BusinessException("外箱标签号不存在!");
        }
        ArrayList boxNoList = cartonDoc.get("BoxNo", ArrayList.class);
        log.info("包装管制小盒标签列表: {}", boxNoList);
        for (Document condition : conditionList) {
            log.info("包装管制约束条件: {}", condition);

            Map map = (Map) condition.get("产线");
            String lineName = "";
            if (map != null) {
                lineName = map.get("name").toString();
                lineName = lineName.replace("线", "");
                if (lineName.length() == 2) {
                    lineName = "0" + lineName;
                }
            }

            map = (Map) condition.get("限制条件");
            String value = "", effect1 = "", effect2 = "";
            if (map != null) {
                value = map.get("value").toString();
                effect1 = condition.get("最小效率") == null ? "" : condition.get("最小效率").toString();
                effect2 = condition.get("最大效率") == null ? "" : condition.get("最大效率").toString();
            }

            Date startDate = condition.getDate("开始时间");
            Date endDate = condition.getDate("结束时间");

            boolean res = false;
            for (int i = 0; i < boxNoList.size(); ++i) {
                Query query = new Query(Criteria.where("SerialNo").is(boxNoList.get(i)));
                Document document = mongoTemplate.findOne(query, Document.class, boxObjId);
                if (document == null)
                    continue;

                if (!ObjectUtils.isEmpty(lineName)) {   /** 产线 */
                    if (!lineName.equals(document.getString("Line"))) {
                        continue;
                    }
                }

                /** 效率限制 */
                if ("is".equals(value) && !ObjectUtils.isEmpty(effect1)) {
                    if (!effect1.equals(document.getString("Efficiency"))) {
                        continue;
                    }
                } else if ("ne".equals(value) && !ObjectUtils.isEmpty(effect1)) {
                    if (effect1.equals(document.getString("Efficiency"))) {
                        continue;
                    }
                } else if ("gt".equals(value) && !ObjectUtils.isEmpty(effect1)) {
                    float effect = Float.parseFloat(document.getString("Efficiency"));
                    float effect1Int = Float.parseFloat(effect1);
                    if (effect <= effect1Int) {
                        continue;
                    }
                } else if ("gte".equals(value) && !ObjectUtils.isEmpty(effect1)) {
                    float effect = Float.parseFloat(document.getString("Efficiency"));
                    float effect1Int = Float.parseFloat(effect1);
                    if (effect < effect1Int) {
                        continue;
                    }
                } else if ("lt".equals(value) && !ObjectUtils.isEmpty(effect2)) {
                    float effect = Float.parseFloat(document.getString("Efficiency"));
                    float effect2Int = Float.parseFloat(effect2);
                    if (effect >= effect2Int) {
                        continue;
                    }
                } else if ("lte".equals(value) && !ObjectUtils.isEmpty(effect2)) {
                    float effect = Float.parseFloat(document.getString("Efficiency"));
                    float effect2Int = Float.parseFloat(effect2);
                    if (effect > effect2Int) {
                        continue;
                    }
                } else if ("between".equals(value) && !ObjectUtils.isEmpty(effect1) && !ObjectUtils.isEmpty(effect2)) {
                    float effect = Float.parseFloat(document.getString("Efficiency"));
                    float effect1Int = Float.parseFloat(effect1);
                    float effect2Int = Float.parseFloat(effect2);
                    if (effect > effect2Int || effect < effect1Int) {
                        continue;
                    }
                } else if ("around".equals(value) && !ObjectUtils.isEmpty(effect1) && !ObjectUtils.isEmpty(effect2)) {
                    float effect = Float.parseFloat(document.getString("Efficiency"));
                    float effect1Int = Float.parseFloat(effect1);
                    float effect2Int = Float.parseFloat(effect2);
                    if (effect <= effect2Int && effect >= effect1Int) {
                        continue;
                    }
                }

                /** 开始时间结束时间 */
                String CreateTimeStr = document.getString("CreateTime");
                try {
                    Date createTime = sdf.parse(CreateTimeStr);
                    long createTimeL = createTime.getTime();
                    if (startDate != null) {
                        long temp = startDate.getTime();
                        if (createTimeL < temp) {
                            continue;
                        }
                    }
                    if (endDate != null) {
                        long temp = endDate.getTime();
                        if (temp < createTimeL) {
                            continue;
                        }
                    }
                } catch (ParseException e) {
                    log.error("包装管制时间转换失败: {}", e.getMessage());
                }

                //记录管控标记
                Update update = new Update();
                update.set("是否被管控", true);
                mongoTemplate.updateFirst(Query.query(Criteria.where("_id").is(new ObjectId(cartonDoc.getString("id")))), update, cartonObjId);
                throw new BusinessException("包装管制限制，不允许入库!");
            }
        }
    }

    /**
     * 获取领料数
     *
     * @param planId 工单号
     */
    @Override
    public double getLeftLYNums(String planId) throws BusinessException {
        //查询备料计划
        Document order = mongoTemplate.findById(new ObjectId(planId), Document.class, "entity_64c1d61afb1d976ceaff0d01");
        if (order == null) {
            throw new BusinessException("计划单不存在!");
        }
        double planLyNum = 0;
        List<Document> mList = order.getList("物料清单", Document.class);
        for (Document d : mList) {
            String code = d.getString("材料编码");
            if (code.startsWith("1101") || code.startsWith("10")) {
                planLyNum = Double.parseDouble(d.getString("计划出库数量"));
                break;
            }
        }
        double lyNum = getLyNum(planId);
        return planLyNum - lyNum;
    }

    /**
     * 获取领料数
     *
     * @param planId 工单号
     */
    @Override
    public void getLeftLYNums(String planId, List<Map> list) throws BusinessException {
        //查询备料计划
        Document order = mongoTemplate.findById(new ObjectId(planId), Document.class, "entity_64c1d61afb1d976ceaff0d01");
        if (order == null) {
            throw new BusinessException("计划单不存在!");
        }
        List<Document> mList = order.getList("物料清单", Document.class);

        for (Map map : list) {
            String mCode = map.get("材料编码").toString();
            String minPckNumStr = null;
            BigDecimal num = new BigDecimal(map.get("数量").toString());
            BigDecimal planLyNum = new BigDecimal(0);
            for (Document d : mList) {
                String code = d.getString("材料编码");
                if (code.equals(mCode)) {
                    planLyNum = planLyNum.add(new BigDecimal(d.getString("计划出库数量")));
                    minPckNumStr = d.getString("最小包装量");
                }
            }
            BigDecimal lyNum = getLyNum(planId, mCode);
            BigDecimal leftNum = planLyNum.subtract(lyNum);
            //最小包装量管控
            if (!ObjectUtils.isEmpty(minPckNumStr)) {
                BigDecimal minPckNum = new BigDecimal(minPckNumStr);
                BigDecimal[] temps = leftNum.divideAndRemainder(minPckNum);
                BigDecimal factor = temps[1].compareTo(BigDecimal.ZERO) > 0 ? temps[0].add(BigDecimal.ONE) : temps[0];
                leftNum = factor.multiply(minPckNum);
            }
            double left = num.subtract(leftNum).doubleValue();
            if (left > 0) throw new BusinessException(-1, mCode + " 超出计划领用：" + left);
        }
    }

    @Override
    public void getLeftLYNumsByType(String planId, List<Map> list) throws BusinessException {
        //查询备料计划
        Document order = mongoTemplate.findById(new ObjectId(planId), Document.class, "entity_64c1d61afb1d976ceaff0d01");
        if (order == null) {
            throw new BusinessException("计划单不存在!");
        }
        List<Document> mList = order.getList("物料清单", Document.class);
        for (Map map : list) {
            String mType = map.get("材料分类").toString();
            String mCode = map.get("材料编码").toString();
            BigDecimal num = new BigDecimal(map.get("数量").toString());
            if (num.compareTo(BigDecimal.ZERO) <= 0) {
                continue;
            }
            BigDecimal planLyNum = new BigDecimal(0);
            for (Document d : mList) {
                String code = d.getString("材料编码");
                if (code.startsWith(mCode)) {
                    planLyNum = planLyNum.add(new BigDecimal(d.getString("计划出库数量")));
                }
            }
            BigDecimal lyNum = getLyNum(planId, mCode, true);
            BigDecimal leftNum = planLyNum.subtract(lyNum);
            log.error("--planLyNum-- :"+planLyNum);
            log.error("--lyNum-- :"+lyNum);
//            //最小包装量管控
//            if (!ObjectUtils.isEmpty(minPckNumStr)) {
//                BigDecimal minPckNum = new BigDecimal(minPckNumStr);
//                BigDecimal[] temps = leftNum.divideAndRemainder(minPckNum);
//                BigDecimal factor = temps[1].compareTo(BigDecimal.ZERO) > 0 ? temps[0].add(BigDecimal.ONE) : temps[0];
//                leftNum = factor.multiply(minPckNum);
//            }
            double left = num.subtract(leftNum).doubleValue();
            if (left > 0) throw new BusinessException(-1, mType + " 超出计划领用：" + left);
        }
    }

    //查询已领物料
    private BigDecimal getLyNum(String planId, String mCode, boolean isLike) {
        BigDecimal lyNum = new BigDecimal(0);
        BigDecimal tyNum = new BigDecimal(0);
        Criteria criteria = Criteria.where("所属备料计划单.id").is(new ObjectId(planId))
                .and("是否已同步").is(true)
                .and("是否已冲销").ne(true).and("状态").ne("撤销").and("isDelete").ne(YesOrNo.YES.ordinal());
        criteria = isLike ? criteria.and("物料清单.编码").regex("^" + mCode) : criteria.and("物料清单.编码").is(mCode);

        List<Document> lyList = mongoTemplate.find(new Query(criteria), Document.class, "entity_64c725d64d1a5541d57a186f");
        for (Document d : lyList) {
            List<Document> nList = d.getList("物料清单", Document.class);
            for (Document m : nList) {
                String code = m.getString("编码");
                if ((isLike && code.startsWith(mCode)) || mCode.equals(code))
                    lyNum = lyNum.add(new BigDecimal(m.get("数量").toString()));
            }
            //退料
            Criteria criteria1 = Criteria.where("领料单.id").is(new ObjectId(d.getString("id")))
                    .and("状态").is("完成").and("isDelete").ne(YesOrNo.YES.ordinal());
            criteria1 = isLike ? criteria1.and("物料清单.编码").regex("^" + mCode) : criteria1.and("物料清单.编码").is(mCode);
            List<Document> tyList = mongoTemplate.find(new Query(criteria1), Document.class, "entity_64c7532c4d1a5541d57a1885");
            for (Document e : tyList) {
                List<Document> lList = e.getList("物料清单", Document.class);
                for (Document m : lList) {
                    String code = m.getString("编码");
                    if ((isLike && code.startsWith(mCode)) || mCode.equals(code))
                        tyNum = tyNum.add(new BigDecimal(m.get("数量").toString()));
                }
            }
        }
        return lyNum.subtract(tyNum);
    }

    //查询已领物料
    private double getLyNum(String planId) {
        double lyNum = 0;
        Query query = new Query(Criteria.where("所属备料计划单.id").is(new ObjectId(planId))
//                .and("物料清单.编码").regex(pattern)
                .and("调出仓库.id").in(new ObjectId("64e6adfaac0d9088705cf51f"), new ObjectId("64e6adf9ac0d9088705cf3b6"), new ObjectId("64e6adf8ac0d9088705cf239"))
                .and("是否已冲销").ne(true).and("状态").ne("撤销").and("isDelete").ne(YesOrNo.YES.ordinal()));
        List<Document> lyList = mongoTemplate.find(query, Document.class, "entity_64c725d64d1a5541d57a186f");
        for (Document d : lyList) {
            List<Document> nList = d.getList("物料清单", Document.class);
            for (Document m : nList) {
                lyNum += Double.parseDouble(m.get("数量").toString());
            }
        }
        return lyNum;
    }

    //查询已领物料
    private BigDecimal getLyNum(String planId, String mCode) {
        BigDecimal lyNum = new BigDecimal(0);
        BigDecimal tyNum = new BigDecimal(0);
        Query query = new Query(Criteria.where("所属备料计划单.id").is(new ObjectId(planId))
                .and("物料清单.编码").is(mCode)
                .and("是否已冲销").ne(true).and("状态").ne("撤销").and("isDelete").ne(YesOrNo.YES.ordinal()));
        List<Document> lyList = mongoTemplate.find(query, Document.class, "entity_64c725d64d1a5541d57a186f");
        for (Document d : lyList) {
            List<Document> nList = d.getList("物料清单", Document.class);
            for (Document m : nList) {
                if (mCode.equals(m.getString("编码")))
                    lyNum = lyNum.add(new BigDecimal(m.get("数量").toString()));
            }
            //退料
            query = new Query(Criteria.where("领料单.id").is(new ObjectId(d.getString("id")))
                    .and("物料清单.编码").is(mCode)
                    .and("状态").is("完成").and("isDelete").ne(YesOrNo.YES.ordinal()));
            List<Document> tyList = mongoTemplate.find(query, Document.class, "entity_64c7532c4d1a5541d57a1885");
            for (Document e : tyList) {
                List<Document> lList = e.getList("物料清单", Document.class);
                for (Document m : lList) {
                    if (mCode.equals(m.getString("编码")))
                        tyNum = tyNum.add(new BigDecimal(m.get("数量").toString()));
                }
            }
        }
        return lyNum.subtract(tyNum);
    }

    //查询下发物料
    private double getDistributeNum(String planId) {
        String distributeTableName = "entity_64c7642c2521ce161ab7762b";
        double distributeNum = 0;
        Query query = new Query(Criteria.where("所属备料计划单.id").is(new ObjectId(planId))
                .and("是否已同步").is(true)
                //        .and("调出仓库.id").in(new ObjectId("64e6adfaac0d9088705cf51f"), new ObjectId("64e6adf9ac0d9088705cf3b6"), new ObjectId("64e6adf8ac0d9088705cf239"))
                .and("是否已冲销").ne(true).and("状态").ne("撤销").and("isDelete").ne(YesOrNo.YES.ordinal()));
        List<Document> distributeList = mongoTemplate.find(query, Document.class, distributeTableName);
        if (ObjectUtils.isEmpty(distributeList)) {
            return distributeNum;
        }
        for (Document document : distributeList) {
            List<Document> detailtList = document.getList("物料清单", Document.class);
            if (ObjectUtils.isEmpty(detailtList)) {
                continue;
            }
            for (Document detail : detailtList) {
                String code = detail.get("编码").toString();
                if (code.startsWith("1101") || code.startsWith("10")) {
                    distributeNum = new BigDecimal(detail.get("数量").toString()).add(new BigDecimal(String.valueOf(distributeNum))).doubleValue();
                }
            }
        }
        return distributeNum;
    }


    /**
     * 获取剩余可入库数
     *
     * @param orderId 工单号
     */
    @Override
    public double getLeftRKNums(String orderId) throws BusinessException {
        //查询订单
        Document order = mongoTemplate.findById(new ObjectId(orderId), Document.class, "entity_64c1d1b6fb1d976ceaff0cfc");
        if (order == null) {
            throw new BusinessException(-1, "订单不存在!");
        }
        List<Document> mList = order.getList("订单明细", Document.class);
        //计划产出数量
        double planRKNum = Double.parseDouble(mList.get(0).getString("计划产出数量"));

        //已入库成品数量
        double rkNum = 0;
        Query query = new Query(Criteria.where("生产订单.id").is(new ObjectId(orderId))
                .and("是否已同步").is(true)
                .and("是否已冲销").ne(true).and("isDelete").ne(YesOrNo.YES.ordinal()));
        List<Document> rkList = mongoTemplate.find(query, Document.class, "entity_64c759272521ce161ab77627");
        for (Document m : rkList) {
            Object lObj = m.get("成品列表");
            List<ObjectId> ids = new ArrayList<>();
            if (lObj != null && lObj instanceof Collection) {
                List<Object> lObjList = (List<Object>) lObj;
                for (Object x : lObjList) {
                    if (x instanceof ObjectId) {
                        ids.add((ObjectId) x);
                    } else if (x instanceof String) {
                        ids.add(new ObjectId(x + ""));
                    }
                }
            }
            if (lObj != null) {
                List<Document> list = mongoTemplate.find(Query.query(Criteria.where("_id").in(ids)),
                        Document.class, "entity_64bf6f57558136382dc87f79");
                rkNum += list.stream().mapToDouble(d -> Double.parseDouble(d.get("Qty").toString())).sum();
            }
        }

        //已入库碎片
        Query query1 = new Query(Criteria.where("生产订单.id").is(new ObjectId(orderId))
                .and("是否已同步").is(true)
                .and("是否已冲销").ne(true).and("isDelete").ne(YesOrNo.YES.ordinal()));
        List<Document> rkList1 = mongoTemplate.find(query1, Document.class, "entity_64fe837849d2711ab1f885b8");
        for (Document m : rkList1) {
            List<Document> l = m.getList("物料清单", Document.class);
            if (l != null) {
                rkNum += l.stream().mapToDouble(d -> Double.parseDouble(d.get("辅数量").toString())).sum();
            }
        }
        //计划可入余量
        double leftPlanN = planRKNum - rkNum;


        String orderCode = order.getString("工单编号");
        Document plan = mongoTemplate.findOne(Query.query(Criteria.where("isDelete").ne(1).and("来源单据号").is(orderCode)), Document.class, "entity_64c1d61afb1d976ceaff0d01");
        if (plan == null) {
            throw new BusinessException(-1, "计划单不存在!");
        }
        //下发料数
        double distributeNum = getDistributeNum(plan.getString("id"));
        //下发料可入余量
        double leftDistributeNum = distributeNum - rkNum;
        //领料量
//        double lyNum = getLyNum(plan.getString("id"));
        //领料可入余量
        //double leftLyN = lyNum - rkNum;
        return Math.min(leftPlanN, leftDistributeNum);
    }

    @Override
    public Map<String, Double> getInLineNum(String orderNo) throws BusinessException {
        Map<String, Double> map = new HashMap<>();
        Double siliconWaferNum = 0D;
        Double screenNum = 0D;
        Double silverPasteNum = 0D;
        Query query = new Query(Criteria.where("工单号").is(orderNo)
                .and("isDelete").ne(YesOrNo.YES.ordinal()));
        List<Document> lyList = mongoTemplate.find(query, Document.class,
                "entity_64c7642c2521ce161ab7762b");
        for (Document d : lyList) {
            List<Document> nList = d.getList("物料清单", Document.class);
            for (Document m : nList) {
                double count = Double.parseDouble(m.get("数量").toString());
                String materialCode = m.get("编码").toString();
                if(materialCode.startsWith("1102")){
                    silverPasteNum = silverPasteNum + count;
                }else if(materialCode.startsWith("1103")){
                    screenNum = screenNum + count;
                }else if(materialCode.startsWith("1101")){
                    siliconWaferNum = siliconWaferNum + count;
                }
            }
        }
        map.put("网版投入",screenNum);
        map.put("浆料投入",silverPasteNum);
        map.put("硅片投入",siliconWaferNum);
        return map;
    }

    @Override
    public Double getInProductWareHouseNum(String orderId) throws BusinessException {
        double rkNum = 0;
        Query query = new Query(Criteria.where("生产订单.id").is(new ObjectId(orderId))
                .and("是否已同步").is(true)
                .and("是否已冲销").ne(true).and("isDelete").ne(YesOrNo.YES.ordinal()));
        List<Document> rkList = mongoTemplate.find(query, Document.class, "entity_64c759272521ce161ab77627");
        for (Document m : rkList) {
            List<String> l = m.getList("成品列表", String.class);
            if (l != null) {
                List<Document> list = mongoTemplate.find(Query.query(Criteria.where("_id").in(l.stream().map(ObjectId::new).collect(Collectors.toList()))), Document.class, "entity_64bf6f57558136382dc87f79");
                rkNum += list.stream().mapToDouble(d -> Double.parseDouble(d.get("Qty").toString())).sum();
            }
        }
        return rkNum;
    }

    @Override
    public Double getInFragmentWareHouseNum(String orderId) throws BusinessException {
        double rkNum = 0;
        Query query1 = new Query(Criteria.where("生产订单.id").is(new ObjectId(orderId))
                .and("是否已同步").is(true)
                .and("是否已冲销").ne(true).and("isDelete").ne(YesOrNo.YES.ordinal()));
        List<Document> rkList1 = mongoTemplate.find(query1, Document.class, "entity_64fe837849d2711ab1f885b8");
        for (Document m : rkList1) {
            List<Document> l = m.getList("物料清单", Document.class);
            if (l != null) {
                rkNum += l.stream().mapToDouble(d -> Double.parseDouble(d.get("辅数量").toString())).sum();
            }
        }
        return rkNum;
    }

    @Override
    public void cancelGraphiteBoat(String objectId, String tableId, String entityId) throws BusinessException {
        Query query = Query.query(Criteria.where("_id").is(entityId)
                .and("isDelete").is(YesOrNo.NO.ordinal()).and("是否可用").ne("否"));
        Document document = mongoTemplate.findOne(query, Document.class, "entity_" + objectId);
        if (document == null) {
            return;
        }
        String boatCode = document.get("舟号").toString();
        Update update = new Update();
        update.set("是否可用", "否");
        mongoTemplate.updateFirst(query, update, "entity_" + objectId);
        Query query1 = new Query(Criteria.where("舟号").is(boatCode)
                .and("isDelete").is(YesOrNo.NO.ordinal()));
        Update update1 = new Update();
        update1.set("是否可用", "否");
        update1.set("下线时间", new Date());
        mongoTemplate.updateFirst(query1, update1, "entity_" + tableId);
    }

    public void clearAlarm(String objectId, String entityId) throws BusinessException {
        Query query = Query.query(Criteria.where("_id").is(entityId)
                .and("isDelete").is(YesOrNo.NO.ordinal()).and("状态").ne("已解决"));
        Document document = mongoTemplate.findOne(query, Document.class, "entity_" + objectId);
        if (ObjectUtils.isEmpty(document)) {
            return;
        }
        Update update = new Update();
        update.set("updateTime", new Date());
        update.set("状态", "已解决");
        mongoTemplate.updateFirst(query, update, "entity_" + objectId);
    }

    /**
     * 线别冲突
     *
     * @param objectId
     * @param entity
     * @throws BusinessException
     */
    @Override
    public void lineConflict(String objectId, EntityData entity) throws BusinessException {
        //bin盒配置
        if ("6614af07f41d1019b30bff49".equals(objectId)) {
            List lines = entity.get("产线", List.class);
            if (ObjectUtils.isEmpty(lines)) return;
            String id = entity.get("id", String.class);
            for(Object item:lines){
                List items = new ArrayList();
                items.add(item);
                Criteria criteria;
                if (!ObjectUtils.isEmpty(id)) {
                    criteria = Criteria.where("_id").ne(new ObjectId(id)).and("产线").all(items).and("isDelete").ne(YesOrNo.YES.ordinal());
                } else {
                    criteria = Criteria.where("产线").all(items).and("isDelete").ne(YesOrNo.YES.ordinal());
                }
                boolean exists = mongoTemplate.exists(Query.query(criteria), "entity_" + objectId);
                if (exists) {
                    throw new BusinessException(-1, "该产线已存在");
                }
            }
        }


    }

    @Override
    public Map lookOrderSummary(CustomActionParam param)  throws BusinessException{
        String objCode = param.getObjCode();
        String entityId = param.getEntityId();
        Document order = ebs.getEntity(objCode, entityId, null, false);
        String orderNo = order.get("工单编号").toString();
        Map data = new HashMap();
        data.put("obj", mongoTemplate.findById("663b16bedf923a5aa0888008", Obj.class));
        Double inProductWareHouseNum = this.getInProductWareHouseNum(entityId);
        Double inFragmentWareHouseNum = this.getInFragmentWareHouseNum(entityId);
        List<Map> contentList = new ArrayList<>();
        Map content = new HashMap();
        content.put("成品产出",inProductWareHouseNum);
        content.put("碎片产出",inFragmentWareHouseNum);
        Map<String, Double> inLineNum = this.getInLineNum(orderNo);
        content.putAll(inLineNum);
        contentList.add(content);
        data.put("content",contentList);
        return data;
    }

    private String getObjId(String objName) {
        Document document = mongoTemplate.findOne(Query.query(Criteria.where("对象名称").is(objName).and("isDelete").is(YesOrNo.NO.ordinal())), Document.class, "entity_64b204a915f95e78f2193e0e");
        if (document == null) log.error("---:" + objName);
        return document == null ? null : document.getString("对象id");
    }


    /**
     * 更新成品数据状态
     *
     * @param objId
     */
//    @Async
    public void updateCPStock(Document document, String objId, Map map) {
        if (!"64c759272521ce161ab77627".equals(objId)) return;
        String status = map.getOrDefault("状态", "").toString();

        boolean isOut;
        if ("完成".equals(status)) {
            isOut = true;
        } else if ("撤销".equals(status)) {
            isOut = false;
        } else return;

        List<Object> li = document.get("成品列表", List.class);
        List<String> ids = new ArrayList<>();
        if(!CollectionUtils.isEmpty(li)) {
            for (Object obj : li) {
                ids.add(obj.toString());
            }
        }
//        List<String> ids = document.getList("成品列表", String.class);
        if (CommonUtil.listIsBlank(ids)) return;
        List<Pair<Query, Update>> list = new ArrayList<>();
        BulkOperations operations = mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, "entity_64bf6f57558136382dc87f79");
        for (String id : ids) {
            Query query = Query.query(Criteria.where("_id").is(new ObjectId(id)));
            Update update = new Update();
            update.set("是否已出库", isOut);
            update.set("出库单号", isOut ? document.get("入库单号") : null);
            Pair<Query, Update> pair = Pair.of(query, update);
            list.add(pair);
        }
        operations.upsert(list);
        operations.execute();
    }

    /**
     * 更新成品数据状态，针对成品单箱入库（新）
     *
     */
//    @Async
    public void updateCPStockNew(Document document, String objId, Map map) {
        if (!"68f1f7e29611b117745d5ae4".equals(objId)) return;
        String status = map.getOrDefault("状态", "").toString();

        boolean isOut;
        if ("完成".equals(status)) {
            isOut = true;
        } else if ("撤销".equals(status)) {
            isOut = false;
        } else return;

        String cartonNo = document.getString("箱号");
        if (StringUtils.isBlank(cartonNo)) return;

        Update update = new Update();
        update.set("是否已出库", isOut);
        update.set("出库单号", isOut ? document.get("入库单号") : null);

        Query updateQuery = new Query(EntityUtils.newCriteria().and("CartonNo").is(cartonNo));
        mongoTemplate.updateFirst(updateQuery, update, "entity_" + "68ecb895903e14692f06f8fa");
    }

    /**
     * 更新原材料库存
     *
     * @param objId
     */
//    @Async
    public void updateYCLStock(Document document, String objId, Map map) throws BusinessException {
        Double count = EntityUtils.safeGetDouble(document, "被推次数");
        if(count != null && count > 1) {
            log.error("单据[{}]已接收推送，不能被重复推送更新！", document);
            throw new BusinessException("单据已接收推送，不能被重复推送更新！");
        }
        String status = map.getOrDefault("状态", "").toString();
        if (!"完成".equals(status)) return;
        if (document == null) return;
        if ("完成".equals(document.getString("状态"))) return;
        List<Document> list = document.getList("物料清单", Document.class);
        if (CommonUtil.listIsBlank(list)) return;
        //BOM、非BOM领用
        if ("64c725d64d1a5541d57a186f".equals(objId) || "64ca10ce49c5bd1b9d0f6171".equals(objId)) {
            boolean isBOM = "64c725d64d1a5541d57a186f".equals(objId);
            for (Document m : list) {
                Document stock = m.get("选择库存", Document.class);
                String stockId = stock.get("id").toString();
                // 兼容：查询库存原数据。原来的数据被简化了
                stock = ebs.getEntity("64dc91ca7e0df27401298db1", stockId, null, false);

                BigDecimal num = BigDecimal.valueOf(Double.valueOf(m.get("数量").toString()));
                String code = stock.getString("物料");
                String batch = stock.getString("批号");
                Document color = stock.get("颜色(电池)", Document.class);
                Document clazz = stock.get("等级(组件&电池&硅片)", Document.class);
                Document ky = stock.get("电流电压(组件&电池)", Document.class);
                Document gl = stock.get("功率(组件&电池)", Document.class);
                Document cs = stock.get("厂商(BOM物料)", Document.class);
                Document kh = stock.get("代工客户(BOM物料)", Document.class);
                Criteria cond = Criteria.where("批号").is(batch).and("物料").is(code).and("是否BOM").is(isBOM);

                List<Criteria> criteriaList = new ArrayList<>();
                criteriaList.add(Criteria.where("tenantId").is(tenantId).and("isDelete").ne(YesOrNo.YES.ordinal()));
                if (color != null) criteriaList.add(Criteria.where("颜色(电池)").is(color.get("档案编码")));
                if (clazz != null)
                    criteriaList.add(Criteria.where("等级(组件&电池&硅片)").is(clazz.get("档案编码")));
                if (ky != null) criteriaList.add(Criteria.where("电流电压(组件&电池)").is(ky.get("档案编码")));
                if (gl != null) criteriaList.add(Criteria.where("功率(组件&电池)").is(gl.get("档案编码")));
                if (cs != null) criteriaList.add(Criteria.where("厂商(BOM物料)").is(cs.get("供应商编码")));
                if (kh != null) criteriaList.add(Criteria.where("代工客户(BOM物料)").is(kh.get("客户编码")));
                cond.andOperator(criteriaList);

                Query query = Query.query(cond);
                Document oldStock = mongoTemplate.findOne(query, Document.class, "entity_64e1b2c3ed614b463d719eae");
                if (oldStock != null) {
                    double oldNum = Double.valueOf(oldStock.get("数量").toString());
                    Update update = new Update();
                    update.set("数量", BigDecimal.valueOf(oldNum).add(num).doubleValue());
                    update.set("累计领料数量", BigDecimal.valueOf(Double.valueOf(oldStock.getOrDefault("累计领料数量", 0).toString())).add(num).doubleValue());
                    mongoTemplate.updateFirst(query, update, "entity_64e1b2c3ed614b463d719eae");
                } else {
                    Map newStock = stock2Map(stock);
                    newStock.put("数量", num.doubleValue());
                    newStock.put("累计领料数量", num.doubleValue());
                    newStock.put("累计退料数量", 0);
                    newStock.put("累计下发数量", 0);
                    newStock.put("累计冲销数量", 0);
                    newStock.put("是否BOM", isBOM);
                    newStock.put("tenantId", tenantId);
                    newStock.put("createTime", new Date());
                    newStock.put("isDelete", 0);
                    newStock.remove("id");
                    newStock.remove("_id");
                    mongoTemplate.save(newStock, "entity_64e1b2c3ed614b463d719eae");
                }
            }
        }
        //BOM、非BOM退料
        else if ("64c7532c4d1a5541d57a1885".equals(objId) || "64ca198249c5bd1b9d0f6174".equals(objId)) {
            for (Document m : list) {
                Map stock = (Map) m.get("物料类型");
                if (stock == null) continue;
                String id = stock.get("id").toString();
                BigDecimal num = BigDecimal.valueOf(Double.valueOf(m.getOrDefault("数量", "0").toString()));
                Query query = Query.query(Criteria.where("_id").is(new ObjectId(id)));
                Document oldStock = mongoTemplate.findOne(query, Document.class, "entity_64e1b2c3ed614b463d719eae");
                double oldNum = Double.valueOf(oldStock.get("数量").toString());
                Update update = new Update();
                double currNum = BigDecimal.valueOf(oldNum).subtract(num).doubleValue();
                update.set("数量", currNum);
                update.set("累计退料数量", BigDecimal.valueOf(Double.valueOf(oldStock.getOrDefault("累计退料数量", 0).toString())).add(num).doubleValue());
                mongoTemplate.updateFirst(query, update, "entity_64e1b2c3ed614b463d719eae");
            }
        }
        // 更新三方推送次数
        Update update = new Update();
        if(count != null) {
            count = count + 1D;
        } else {
            count = 1D;
        }
        update.set("被推次数", count);
        mongoTemplate.updateFirst(Query.query(Criteria.where("_id").is(new ObjectId(document.get("id").toString()))),
                update, "entity_" + objId);
    }

    /**
     * 更新无价值物料库存
     *
     * @param objId
     */
//    @Async
    public void updateLowStock(Document document, String objId, Map map) throws BusinessException {
        Double count = EntityUtils.safeGetDouble(document, "被推次数");
        if(count != null && count > 1) {
            log.error("单据[{}]已接收推送，不能被重复推送更新！", document);
            throw new BusinessException("单据已接收推送，不能被重复推送更新！");
        }
        String status = map.getOrDefault("状态", "").toString();
        if (!"完成".equals(status)) return;
        if (document == null) return;
        if ("完成".equals(document.getString("状态"))) return;
        List<Document> list = document.getList("物料清单", Document.class);
        if (CommonUtil.listIsBlank(list)) return;

        //领用
        if ("64dda2873a43204e2138513e".equals(objId)) {
            for (Document m : list) {
                Document stock = m.get("选择库存", Document.class);
                BigDecimal num = BigDecimal.valueOf(Double.valueOf(m.get("数量").toString()));
                String code = stock.getString("物料");
                String batch = stock.getString("批号");
                Criteria cond = Criteria.where("批号").is(batch).and("物料").is(code).
                        and("tenantId").is(tenantId);
                Query query = Query.query(cond);
                Document oldStock = mongoTemplate.findOne(query, Document.class, "entity_64e1b38aed614b463d719eb2");
                if (oldStock != null) {
                    double oldNum = Double.valueOf(oldStock.get("数量").toString());
                    Update update = new Update();
                    update.set("数量", BigDecimal.valueOf(oldNum).add(num).doubleValue());
                    mongoTemplate.updateFirst(query, update, "entity_64e1b38aed614b463d719eb2");
                } else {
                    Map newStock = stock2Map(stock);
                    newStock.put("数量", num.doubleValue());
                    newStock.put("tenantId", tenantId);
                    newStock.put("createTime", new Date());
                    newStock.put("isDelete", 0);
                    newStock.remove("id");
                    newStock.remove("_id");
                    mongoTemplate.save(newStock, "entity_64e1b38aed614b463d719eb2");
                }
            }
        }
        //退料
        else if ("64dda28f28f8c812823f5a83".equals(objId)) {
            for (Document m : list) {

                Map stock = (Map) m.get("物料类型");
                if (stock == null) continue;
                String id = stock.get("id").toString();
                BigDecimal num = BigDecimal.valueOf(Double.valueOf(m.getOrDefault("数量", "0").toString()));
                Query query = Query.query(Criteria.where("_id").is(new ObjectId(id)));
                Document oldStock = mongoTemplate.findOne(query, Document.class, "entity_64e1b38aed614b463d719eb2");
                double oldNum = Double.valueOf(oldStock.get("数量").toString());
                Update update = new Update();
                double currNum = BigDecimal.valueOf(oldNum).subtract(num).doubleValue();
                update.set("数量", currNum);
                mongoTemplate.updateFirst(query, update, "entity_64e1b38aed614b463d719eb2");

            }
        }

        // 更新三方推送次数
        Update update = new Update();
        if(count != null) {
            count = count + 1D;
        } else {
            count = 1D;
        }
        update.set("被推次数", count);
        mongoTemplate.updateFirst(Query.query(Criteria.where("_id").is(new ObjectId(document.get("id").toString()))),
                update, "entity_" + objId);
    }

    private Map stock2Map(Document stock) {
        Map newStock = new HashMap(stock);
        Document d1 = stock.get("辅助单位", Document.class);
        Document d2 = stock.get("代工客户(BOM物料)", Document.class);
        Object ck = stock.get("仓库");
//        Document d3 = stock.get("仓库", Document.class);
        Document d4 = stock.get("厂商(BOM物料)", Document.class);
        Document d5 = stock.get("等级(组件&电池&硅片)", Document.class);
        Document d6 = stock.get("颜色(电池)", Document.class);
        Document d7 = stock.get("功率(组件&电池)", Document.class);
        Document d8 = stock.get("电流电压(组件&电池)", Document.class);
        newStock.put("辅助单位", d1 == null ? null : d1.get("单位编码"));
        newStock.put("代工客户(BOM物料)", d2 == null ? null : d2.get("客户编码"));
        newStock.put("仓库", ck == null ? null : (ck instanceof Document) ? ((Document) ck).get("仓库编码") : ck);
        newStock.put("厂商(BOM物料)", d4 == null ? null : d4.get("供应商编码"));
        newStock.put("等级(组件&电池&硅片)", d5 == null ? null : d5.get("档案编码"));
        newStock.put("颜色(电池)", d6 == null ? null : d6.get("档案编码"));
        newStock.put("功率(组件&电池)", d7 == null ? null : d7.get("档案编码"));
        newStock.put("电流电压(组件&电池)", d8 == null ? null : d8.get("档案编码"));
        newStock.put("物料编码", stock.getString("物料编码"));
        return newStock;
    }

}
